package com.sh.data.engine.domain.api.run;


import cn.hutool.extra.spring.SpringUtil;
import com.alibaba.fastjson.JSONObject;
import com.alibaba.fastjson.serializer.SerializerFeature;
import com.google.common.collect.Lists;
import com.sh.data.engine.common.constants.HttpStatus;
import com.sh.data.engine.common.constants.code.BizCodes;
import com.sh.data.engine.common.enumDefinition.DataApiCallStatusEnum;
import com.sh.data.engine.common.util.AESUtil;
import com.sh.data.engine.domain.api.model.domain.DataApiCallRecordDomain;
import com.sh.data.engine.domain.api.model.domain.DataApiTaskResultDomain;
import com.sh.data.engine.domain.api.model.domain.rest.DataApiConfigInfoDomain;
import com.sh.data.engine.domain.api.util.DataApiUtil;
import lombok.Data;
import lombok.SneakyThrows;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang.exception.ExceptionUtils;
import org.apache.commons.lang.time.DateFormatUtils;

import java.util.Date;
import java.util.Objects;

/**
 * @author : fuchen
 * @date : 2022/1/25 14:21
 */
@Slf4j
public abstract class DataApiTaskExecutor<T> {

    /**
     * 任务配置
     */
    protected DataApiConfigInfoDomain taskConfig;

    /**
     * 任务入参
     */
    protected T params;

    /**
     * api执行记录
     */
    protected DataApiCallRecordDomain apiRecord;

    protected Integer taskStatus;

    /**
     * uuid 记录日志
     */
    protected Long id;

    protected DataApiConfig dataApiConfig = SpringUtil.getBean(DataApiConfig.class);

    protected DataApiTaskExecutor(
        DataApiCallRecordDomain apiRecord, DataApiConfigInfoDomain taskConfig, T params, Long id) {
        this.apiRecord = apiRecord;
        this.taskConfig = taskConfig;
        this.params = params;
        this.id = id;
    }

    protected void beforeRun() {
        String log =
            String.format(
                "[%s] begin to execute task : %s",
                DateFormatUtils.format(new Date(), "HH:mm:ss.SSS"), taskConfig.getApiName());
        DataApiUtil.writeLog(apiRecord, id, Lists.newArrayList(log));
    }

    protected void afterRun() {
        String log =
            String.format(
                "[%s] task : %s finished,taskStatus : %s",
                DateFormatUtils.format(new Date(), "HH:mm:ss.SSS"),
                taskConfig.getApiName(),
                taskStatus);
        DataApiUtil.writeLog(apiRecord, id, Lists.newArrayList(log));
    }

    /**
     * 真正去跑的任务逻辑
     *
     * @return 任务执行状态
     */
    protected abstract DataApiTaskResultDomain doRun() throws Exception;

    /**
     * 检查任务配置，若必要配置缺失，给出提示
     *
     * @return
     */
    protected abstract Boolean checkTaskConfig();

    @SneakyThrows
    public DataApiTaskResultDomain run() {
        beforeRun();

        DataApiTaskResultDomain result;

        Boolean checkTaskConfig = checkTaskConfig();
        if (null != checkTaskConfig && !checkTaskConfig) {
            String log =
                String.format(
                    "[%s] apiName : [%s] configuration is incomplete.",
                    DateFormatUtils.format(new Date(), "HH:mm:ss.SSS"), taskConfig.getApiName());
            DataApiUtil.writeLog(apiRecord, id, Lists.newArrayList(log));

            result =
                DataApiTaskResultDomain.builder()
                    // .apiId(taskConfig.getApiId())
                    .status(DataApiCallStatusEnum.PARAM_ERR.getStatus())
                    .build();
        } else {
            try {
                result = doRun();
            } catch (Exception e) {
                log.error(e.getMessage(), e);

                String log =
                    String.format(
                        "[%s] apiName : [%s] executed failed.",
                        DateFormatUtils.format(new Date(), "HH:mm:ss.SSS"), taskConfig.getApiName());
                DataApiUtil.writeLog(
                    apiRecord, id, Lists.newArrayList(log, ExceptionUtils.getFullStackTrace(e)));

                result =
                    DataApiTaskResultDomain.builder()
                        .apiId(taskConfig.getId())
                        .status(DataApiCallStatusEnum.SYSTEM_ERR.getStatus())
                        .build();
            }
        }

        this.taskStatus = result.getStatus();

        Object output = result.getOutput();

        // 测试脚本不需要处理
        Integer isSecurity = taskConfig.getIsSecurity();

        // 组合成数据集成引擎返回的数据格式
        RestResponseEntity<Object> restResponseEntity;
        if (Objects.equals(taskStatus, DataApiCallStatusEnum.SUCCESS.getStatus())) {
            restResponseEntity = new RestResponseEntity<>(output);
            Object data = restResponseEntity.getData();
            if (Objects.nonNull(apiRecord) && Objects.nonNull(isSecurity) && isSecurity.equals(1)) {
                Integer pageable = taskConfig.getPageable();
                String dataApiKey = dataApiConfig.getDataApiKey();
                String dataApiSecretType = dataApiConfig.getDataApiSecretType();
                output = AESUtil.encrypt(data.toString(), dataApiKey, dataApiSecretType);
                if (pageable == 1) {
                    String jsonString = JSONObject.toJSONStringWithDateFormat(data, "yyyy-MM-dd HH:mm:ss",
                        SerializerFeature.WriteMapNullValue);
                    output = AESUtil.encrypt(jsonString, dataApiKey, dataApiSecretType);
                }
                restResponseEntity.setData(output);
            }
        } else {
            restResponseEntity = new RestResponseEntity<>("请求失败", output);
        }
        result.setOutput(restResponseEntity);

        afterRun();

        return result;
    }

    @Data
    public static class RestResponseEntity<T> {

        private int code = BizCodes.SUCCESS.getCode();

        private int status = HttpStatus.OK.value();

        private String msg;

        private T data;

        public RestResponseEntity() {
        }

        public RestResponseEntity(T data) {
            this.data = data;
        }

        public RestResponseEntity(String message, T data) {
            this.msg = message;
            this.data = data;
        }
    }
}
